

package section2.sparsematmult;
import jgfutil.*; 

import java.util.Random;

public class JGFSparseMatmultOCLBench extends SparseMatmultOCL implements JGFSection2{ 

  public static int nthreads;

  private int size; 
  private static final long RANDOM_SEED = 10101010;

  private static final int SPARSE_NUM_ITER = 200;

  Random R = new Random(RANDOM_SEED);

  float [] x; 
  float [] y; 
  float [] val; 
  int [] col;
  int [] row;
  int [] lowsum;
  int [] highsum;

  public JGFSparseMatmultOCLBench(int nthreads) {
   JGFSparseMatmultOCLBench.nthreads = nthreads;
  }

  public void JGFsetsize(int size){
    this.size = size;

  }

  public void JGFinitialise(){

  x = RandomVector(size, R);
  
  y = new float[size];
  for (int i = 0; i<size; i++)
  {
  	y[i]=0;
  }
  val = new float[size*5];
  col = new int[size*5];
  row = new int[size*5];

  int [] ilow = new int[nthreads];
  int [] iup = new int[nthreads];
  int [] sum = new int[nthreads+1];
  lowsum = new int[nthreads+1];
  highsum = new int[nthreads+1];
  int [] rowt = new int[size*5];
  int [] colt = new int[size*5];
  float [] valt = new float[size*5];
  int sect;

    for (int i=0; i<size*5; i++) {

        // generate random row index (0, M-1)
        row[i] = Math.abs(R.nextInt()) % size;

        // generate random column index (0, N-1)
        col[i] = Math.abs(R.nextInt()) % size;

        val[i] = (float)R.nextFloat();

    }

// reorder arrays for parallel decomposition

    sect = (size + nthreads-1)/nthreads;

    for (int i=0; i<nthreads; i++) {
      ilow[i] = i*sect;
      iup[i] = ((i+1)*sect)-1;
      if(iup[i] > size) iup[i] = size;
    }

    for (int i=0; i<size*5; i++) {
      for (int j=0; j<nthreads; j++) {
        if((row[i] >= ilow[j]) && (row[i] <= iup[j])) { 
          sum[j+1]++; 
        }
      }         
    }

    for (int j=0; j<nthreads; j++) {
      for (int i=0; i<=j; i++) {
         lowsum[j] = lowsum[j] + sum[j-i];
         highsum[j] = highsum[j] + sum[j-i];
      }
    }

    for (int i=0; i<size*5; i++) {
      for (int j=0; j<nthreads; j++) {
        if((row[i] >= ilow[j]) && (row[i] <= iup[j])) {
          rowt[highsum[j]] = row[i];
          colt[highsum[j]] = col[i];
          valt[highsum[j]] = val[i];
          highsum[j]++;
        }
      }
    }

    for (int i=0; i<size*5; i++) {
      row[i] = rowt[i];
      col[i] = colt[i];
      val[i] = valt[i];
    }

  }
 
  public void JGFkernel(){
    ytotal = this.test(y, val, row, col, x, SPARSE_NUM_ITER, lowsum, highsum);
  }

  public void JGFvalidate(){
  }

  public double getResult(int size)
 {

    JGFInstrumentor.addTimer("Section2:SparseMatmult:Kernel", "Iterations",size);

    JGFsetsize(size); 
    JGFinitialise(); 
    JGFkernel(); 
    JGFvalidate(); 
    double res = ytotal;
    JGFtidyup(); 
    return res;
 }

  public void JGFtidyup(){
   System.gc();
  }  



  public void JGFrun(int size){


    JGFInstrumentor.addTimer("Section2:SparseMatmult:Kernel", "Iterations",size);

    JGFsetsize(size); 
    JGFinitialise(); 
    JGFkernel(); 
    JGFvalidate(); 
    JGFtidyup(); 

     
    JGFInstrumentor.addOpsToTimer("Section2:SparseMatmult:Kernel", (float) (SPARSE_NUM_ITER));
    double time = JGFInstrumentor.readTimer("Section2:SparseMatmult:Kernel");
    System.out.print(time+" ");
  }

        private static float[] RandomVector(int N, java.util.Random R)
        {
                float A[] = new float[N];

                for (int i=0; i<N; i++)
                        A[i] = (float) (R.nextFloat() * 1e-6);

                return A;
        }


}
